package com.coumo.ec2tool;

import java.io.File;
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.List;
import com.amazonaws.AmazonServiceException;
import com.amazonaws.services.ec2.AmazonEC2;
import com.amazonaws.services.ec2.AmazonEC2Client;
import com.amazonaws.services.ec2.model.*;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.PropertiesCredentials;

class ec2tool
{
	private AmazonEC2 ec2;
	
	public static void main (String[] args) 
	{
		ec2tool app = new ec2tool();

		try
		{
			app.run (args);
		}
		catch (AmazonServiceException ase)
		{
            System.out.println("Caught Exception: " + ase.getMessage());
            System.out.println("Reponse Status Code: " + ase.getStatusCode());
            System.out.println("Error Code: " + ase.getErrorCode());
            System.out.println("Request ID: " + ase.getRequestId());			
		}

		catch (Exception ioe)
		{
			ioe.printStackTrace();
		}
	};

	private void run (String[] args) throws Exception
	{
		if (args.length == 0 )
		{
			usage();
		}
		
		if (!init (args))
		{
			return;
		}

		if (args[0].equals ("terminate"))
		{
			cmd_terminate (args);
		}
		else if (args[0].equals("run"))
		{
			cmd_run (args);
		}
		else if (args[0].equals("host"))
		{
			cmd_host (args);
		}
		else if ( args[0].equals ("stop") )
		{
			cmd_stop (args);
		}
		else if ( args[0].equals("start"))
		{
			cmd_start (args);
		}
		else if ( args[0].equals("view"))
		{
			cmd_view (args);
		}
		else
		{
			usage();
		}
	}
	
	private boolean init (String[] args) throws Exception
	{
		AWSCredentials credentials;
		File keyFile;
		
		keyFile = new File ("key.properties");
		
		if ( ! keyFile.exists())
		{
			System.out.println ( keyFile.getAbsolutePath() + " not found" );
			return false;
		}
		
		credentials = new PropertiesCredentials(keyFile);
			
		ec2 = new AmazonEC2Client (credentials);
	
		return true;
	}
	
	private static void usage ()
	{
		String s[] = 
		{
			"usage : ",
			"  ec2tool terminate instance1 instance2 ",
			"  ec2tool terminate all",
			"  ec2tool host hostfile",
			"  ec2tool run --AMI=imageid --key-pair=keyName --security-group=sec",
			"              --zone=zonename --dev-map=devmapping --count=count",			
			"  ec2tool view",
			"  ec2tool view zone",
			"  ec2tool view image",
			"  ec2tool view key",
			"  ec2tool view sec-group",
			"  ec2tool view volume",
			"  ec2tool view address"				
		};
		
		for (int i = 0; i < s.length; i++)
		{
			System.out.println(s[i]);
		}
		
		System.exit(0);
	}
	
	/*
	 * run --key=
	 * 		Security Group
	 * 		AMI ID
	 * 		KeyPairs
	 * */	
	private void cmd_run (String[] args) throws Exception
	{
		String key,value;
		String keyName = null, AMI = null;
		String devMap = null, zone = null;
		ArrayList<String> secGroup = new ArrayList<String>();
		int InsCount = 0;
		
		for (int i = 1; i < args.length; i++)
		{
			int ind = args[i].indexOf('=');
			if (ind>0)
			{
				key = args[i].substring(0,ind);
				value = args[i].substring(ind+1);
			}
			else 
			{ 
				continue;
			}
			
			if ( key.equals("--key-pair")) keyName = value;
			else if (key.equals("--security-group")) secGroup.add(value);
			else if (key.equals("--AMI")) AMI = value;
			else if (key.equals("--dev-map")) devMap = value;
			else if (key.equals("--zone")) zone = value;
			else if (key.equals("--count")) InsCount = Integer.parseInt(value);
		}
		
		if (AMI == null || secGroup.size() == 0 || keyName == null)
		{
			System.out.println ("AMI or key-pair or security-group must be specified");
			return;
		}
		
		RunInstancesRequest req = new RunInstancesRequest ();
		
		if (InsCount <1 )
		{
			InsCount = 1;			
		}
		else if (InsCount > 1000 )
		{
			InsCount = 1000;
		}
		
		req.setSecurityGroups ( secGroup );
		req.setKeyName (keyName);
		req.setMaxCount (InsCount);
		req.setMinCount (InsCount);
		req.setImageId (AMI);
		
		if (zone != null)
		{
			req.setPlacement((new Placement()).withAvailabilityZone(zone));
		}
		
		if (devMap != null)
		{
			List<BlockDeviceMapping> devMapping = new ArrayList<BlockDeviceMapping>();
			BlockDeviceMapping bmap = new BlockDeviceMapping();
			bmap.setVirtualName("/dev/sdo");
			bmap.setDeviceName(devMap);
			req.setBlockDeviceMappings(devMapping);
		}
		
		RunInstancesResult result = ec2.runInstances(req);
		System.out.println ( result.toString() );
	}
	/* 
	 * ip hostname
	 * 
	 */
	private void cmd_host (String[] args) throws Exception
	{
		if (args.length != 2)
		{
			usage();
			return;
		}
		
		List<Instance> lst = getInstanceList();

		if (lst == null)
		{
			System.out.println ("host not found");
			return;
		}
		
		FileWriter os = null;
		
		for (Instance i : lst )
		{
			if (i.getState().getCode() != 2)
			{
				continue;
			}
			if (os == null)
			{
				os = new FileWriter (args[1]);
			}
			
			os.write (i.getPublicIpAddress());
			os.write (" ");
			os.write (i.getPublicDnsName());
			os.write ("\r\n");
		}
		
		if (os != null)
		{
			os.close();
		}
	}
	
	private void cmd_view (String[] args) throws Exception
	{		
		if (args.length == 1)
		{
			DescribeInstancesResult result = ec2.describeInstances();			
			List<Reservation> lst = result.getReservations();
		
			for (Reservation j : lst)
			{
				List<Instance> Ins_lst = j.getInstances();
						
				System.out.println ( "[" + j.getReservationId() + "]" );
			
				for (Instance i : Ins_lst)
				{					
					System.out.println ("PublicIP   = " + i.getPublicIpAddress() );
					System.out.println ("PrivateIP  = " + i.getPrivateIpAddress());
					System.out.println ("InstanceID = " + i.getInstanceId() );
					System.out.println ("System     = " + i.getPlatform() );
					System.out.println ("Type       = " + i.getInstanceType() );
					System.out.println ("State      = " + i.getState());
					System.out.println ("");
				}
			}
			
			return;
		}
		
		if (args.length == 3)
		{
			usage();
			return;
		}
		
		if (args[1].equals("zone"))
		{
            DescribeAvailabilityZonesResult result = ec2.describeAvailabilityZones();
            List<AvailabilityZone> lst = result.getAvailabilityZones();
            
            for (AvailabilityZone i : lst)
            {
            	System.out.println ("Name  = " + i.getZoneName() );
            	System.out.println ("State = " + i.getState() );
            	System.out.println ("Region= " + i.getRegionName() );
				System.out.println ("");
            }
            return;
		}
		
		if (args[1].equals ("sec-group") )
		{
			DescribeSecurityGroupsResult result = ec2.describeSecurityGroups();
			List<SecurityGroup> lst = result.getSecurityGroups();
			
			for (SecurityGroup i : lst)
			{
				System.out.println ( i.getGroupName() + " " + i.getDescription());
			}
			return;
		}
		
		if (args[1].equals("key"))
		{
			DescribeKeyPairsResult result = ec2.describeKeyPairs();
			List<KeyPairInfo> lst = result.getKeyPairs();
			for (KeyPairInfo i : lst)
			{
				System.out.println ( i.getKeyName() + " " + i.getKeyFingerprint() );
			}
			return;
		}
		
		if (args[1].equals("address"))
		{
			DescribeAddressesResult result = ec2.describeAddresses();
			List<Address> lst = result.getAddresses();
			for (Address i : lst)
			{
				System.out.println ( i.getPublicIp() + " " + i.getInstanceId() );
			}
			return;
		}
		
		if (args[1].equals("image"))
		{
			DescribeImagesResult result = ec2.describeImages();
			List<Image> lst = result.getImages();
			for (Image i : lst)
			{
				System.out.println ( "ID       = " + i.getImageId());
				System.out.println ( "Location = " + i.getImageLocation() );
				System.out.println ( "Type     = " + i.getImageType() );
				System.out.println ("");
			}
			return;
		}
		
		if (args[1].equals("volume"))
		{
			DescribeVolumesRequest req = new DescribeVolumesRequest ();
			
			DescribeVolumesResult result = ec2.describeVolumes(req);
			
			List<Volume> lst = result.getVolumes();
			
			for (Volume i : lst)
			{
				System.out.println ( "Id    = " + i.getVolumeId() );
				System.out.println ( "Size  = " + i.getSize());
				System.out.println ( "Zone  = " + i.getAvailabilityZone());
				System.out.println ( "State = " + i.getState());
			}
			
			return;
		}
		
		usage();
	}
	
	private void cmd_terminate (String[] args) throws Exception
	{
		List<String> id_list = null;
		
		if (args.length == 1)
		{
			usage();
		}
		
		if (args[1].equals("all"))
		{
			if ( args.length != 2)
			{
				usage();
			}
			
			id_list = getInstanceIdList (-1);
		}
		else
		{
			id_list = new ArrayList <String>();
			
			for ( int i = 1; i < args.length; i++)
			{
				id_list.add ( args[i]);
			}
		}
		
		if (id_list == null)
		{
			System.out.println ("no active instance");
			return;
		}
		
		TerminateInstancesRequest tRequest = new TerminateInstancesRequest();
		tRequest.setInstanceIds( id_list );
		TerminateInstancesResult tResult =  ec2.terminateInstances(tRequest);
		
		System.out.println ( tResult.toString() );		
	}
	
	private void cmd_stop (String[] args) throws Exception
	{
	}
	
	private void cmd_start (String[] args) throws Exception
	{
	}
	
	private List<String> getInstanceIdList (int state)
	{
		List<Instance> lst = getInstanceList();
		List<String> ret = new ArrayList <String>();
		
		if (lst !=null)
		{
			for (Instance i : lst)
			{
				if (state < 0 || state == i.getState().getCode())
				{
					ret.add(i.getInstanceId() );
				}
			}
		}
		
		if (ret.size() == 0 )
		{
			return null;
		}
		else
		{
			return ret;
		}
	}
	
	private List<Instance> getInstanceList()
	{
		List<Instance> ret = new ArrayList<Instance> ();
		
		DescribeInstancesResult result = ec2.describeInstances();			
		
		if (result != null)
		{
			List<Reservation> lst = result.getReservations();
	
			for (Reservation i : lst)
			{
				ret.addAll( i.getInstances() );
			}	
		}
		
		if (ret.size() == 0)
		{
			return null;
		}
		else
		{
			return ret;		
		}
	}
};